/*
 *
 *      Copyright (c) 2018-2025, proj All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the proj developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: proj
 *
 */

package com.ykht.proj.admin.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codingapi.tx.annotation.TxTransaction;
import com.ykht.proj.admin.api.dto.UserDTO;
import com.ykht.proj.admin.api.dto.UserInfo;
import com.ykht.proj.admin.api.entity.*;
import com.ykht.proj.admin.api.vo.MenuVO;
import com.ykht.proj.admin.api.vo.UserVO;
import com.ykht.proj.admin.mapper.SysUserMapper;
import com.ykht.proj.admin.service.*;
import com.ykht.proj.common.core.constant.CacheConstants;
import com.ykht.proj.common.core.constant.CommonConstants;
import com.ykht.proj.common.core.constant.SecurityConstants;
import com.ykht.proj.common.core.util.R;
import com.ykht.proj.common.data.datascope.DataScope;
import com.ykht.proj.common.security.service.ProjUser;
import com.ykht.proj.common.security.util.SecurityUtils;
import com.ykht.proj.coupon.Enum.UserTypeEnum;
import com.ykht.proj.coupon.api.feign.RemoteUserExtService;
import com.ykht.proj.coupon.dto.UserExtDto;
import com.ykht.proj.coupon.vo.BindSjVo;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author proj
 * @date 2017/10/31
 */
@Slf4j
@Service
@AllArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

	private final SysMenuService sysMenuService;

	private final SysRoleService sysRoleService;

	private final SysDeptService sysDeptService;

	private final SysUserRoleService sysUserRoleService;

	private final SysDeptRelationService sysDeptRelationService;

	private final CacheManager cacheManager;

	private final RemoteUserExtService remoteUserExtService;
	/**
	 * 保存用户信息
	 * @param userDto DTO 对象
	 * @return success/fail
	 */
	@Override
	@TxTransaction() // 请求方 要加 isStart = true  被请求的不用加  isStart = true  控制事物 注解
	@Transactional(rollbackFor = Exception.class)
	public SysUser saveUser(UserDTO userDto) {
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
		sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
		sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
		baseMapper.insert(sysUser);
		List<SysUserRole> userRoleList =new  ArrayList();
			SysUserRole userRole = new SysUserRole();
			userRole.setUserId(sysUser.getUserId());
			userRole.setRoleId(userDto.getRole());
		userRoleList.add(userRole);
		boolean b = sysUserRoleService.saveBatch(userRoleList);
		return sysUser;
	}

	/**
	 * 通过查用户的全部信息
	 * @param sysUser 用户
	 * @return
	 */
	@Override
	public UserInfo findUserInfo(SysUser sysUser) {
		UserInfo userInfo = new UserInfo();
		userInfo.setSysUser(sysUser);
		// 设置角色列表 （ID）
		List<Integer> roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId()).stream().map(SysRole::getRoleId)
				.collect(Collectors.toList());
		userInfo.setRoles(ArrayUtil.toArray(roleIds, Integer.class));

		// 设置权限列表（menu.permission）
		Set<String> permissions = new HashSet<>();
		roleIds.forEach(roleId -> {
			List<String> permissionList = sysMenuService.findMenuByRoleId(roleId).stream()
					.filter(menuVo -> StringUtils.isNotEmpty(menuVo.getPermission())).map(MenuVO::getPermission)
					.collect(Collectors.toList());
			permissions.addAll(permissionList);
		});
		userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));
		return userInfo;
	}

	/**
	 * 分页查询用户信息（含有角色信息）
	 * @param page 分页对象
	 * @param userDTO 参数列表
	 * @return
	 */
	@Override
	public IPage getUsersWithRolePage(Page page, UserDTO userDTO) {
		return baseMapper.getUserVosPage(page, userDTO, new DataScope());
	}

	/**
	 * 通过ID查询用户信息
	 * @param id 用户ID
	 * @return 用户信息
	 */
	@Override
	public UserVO selectUserVoById(Integer id) {
		return baseMapper.getUserVoById(id);
	}

	/**
	 * 删除用户
	 * @param sysUser 用户
	 * @return Boolean
	 */
	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#sysUser.username")
	public Boolean deleteUserById(SysUser sysUser) {
		sysUserRoleService.deleteByUserId(sysUser.getUserId());
		this.removeById(sysUser.getUserId());
		return Boolean.TRUE;
	}

	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
	public R<Boolean> updateUserInfo(UserDTO userDto) {
		UserVO userVO = baseMapper.getUserVoByUsername(userDto.getUsername());
		SysUser sysUser = new SysUser();
		if (StrUtil.isNotBlank(userDto.getPassword()) && StrUtil.isNotBlank(userDto.getNewpassword1())) {
			if (ENCODER.matches(userDto.getPassword(), userVO.getPassword())) {
				sysUser.setPassword(ENCODER.encode(userDto.getNewpassword1()));
			}
			else {
				log.info("原密码错误，修改密码失败:{}", userDto.getUsername());
				return R.failed("原密码错误，修改失败");
			}
		}
		sysUser.setPhone(userDto.getPhone());
		sysUser.setUserId(userVO.getUserId());
		sysUser.setAvatar(userDto.getAvatar());
		return R.ok(this.updateById(sysUser));
	}

	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
	public Boolean updateUser(UserDTO userDto) {
		SysUser sysUser = new SysUser();
		BeanUtils.copyProperties(userDto, sysUser);
		sysUser.setUpdateTime(LocalDateTime.now());

		if (StrUtil.isNotBlank(userDto.getPassword())) {
			sysUser.setPassword(ENCODER.encode(userDto.getPassword()));
		}
		this.updateById(sysUser);
		sysUserRoleService
				.remove(Wrappers.<SysUserRole>update().lambda().eq(SysUserRole::getUserId, userDto.getUserId()));
			SysUserRole userRole = new SysUserRole();
			userRole.setUserId(sysUser.getUserId());
			userRole.setRoleId(userDto.getRole());
			userRole.insert();
		return Boolean.TRUE;
	}

	/**
	 * 查询上级部门的用户信息
	 * @param username 用户名
	 * @return R
	 */
	@Override
	public List<SysUser> listAncestorUsers(String username) {
		SysUser sysUser = this.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));

		SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());
		if (sysDept == null) {
			return null;
		}

		Integer parentId = sysDept.getParentId();
		return this.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getDeptId, parentId));
	}

	/**
	 * 获取当前用户的子部门信息
	 * @return 子部门列表
	 */
	private List<Integer> getChildDepts() {
		Integer deptId = SecurityUtils.getUser().getDeptId();
		// 获取当前部门的子部门
		return sysDeptRelationService
				.list(Wrappers.<SysDeptRelation>query().lambda().eq(SysDeptRelation::getAncestor, deptId)).stream()
				.map(SysDeptRelation::getDescendant).collect(Collectors.toList());
	}

	@Override
	public IPage getUsersPage(Page page, UserDTO userDTO) {
		return baseMapper.getUserPage(page, userDTO);
	}

    @Override
    public Map<Long, String> getUserByIds(List<Integer> ids) {
		HashMap<Long, String> resultMap = new HashMap<>();
		for (Integer id : ids) {
			UserVO userVO = this.baseMapper.getUserVoById(id);
			resultMap.put(Long.parseLong(id+""),userVO.getUsername());
		}
        return resultMap;
    }


	@Override
	public R changeSj(UserExtDto userExt) {
//		System.out.println("-----------------"+ SecurityUtilsExt.getSjId());
		System.out.println("-----------------"+ SecurityUtils.getSjId());
//		ProjUser projUser = (ProjUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
//		System.out.println("当前sjid："+projUser.getSjId());
		Cache cache = cacheManager.getCache(CacheConstants.USER_DETAILS);
		String username = SecurityUtils.getUser().getUsername();
		ProjUser oldUser = null,newUser = null;
		try {
			R r = remoteUserExtService.checkChangeSj(userExt);
			if (r.getCode()==CommonConstants.FAIL||r.getData()==null) {
				return R.failed(String.format("切换%s%s", UserTypeEnum.getDescByVal(userExt.getUserType()),"失败"));
			}
			oldUser =  newUser =  (ProjUser) cache.get(username).get();
			newUser.setSjId(userExt.getSjId());
			//更新缓存中用户信息
			cache.put(username, newUser);
			System.out.println(JSONUtil.toJsonStr(cache));
			SysUser sysUser = new SysUser();
			sysUser.setUserId(userExt.getUserId());
			sysUser.setSjIdDefLogin(userExt.getSjId());
			this.updateById(sysUser);

//			//修改security中用户信息.不可行
//			Authentication authentication = SecurityUtils.getAuthentication();
//			SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(newUser, authentication.getCredentials(), authentication.getAuthorities()));
//
//			ProjUser projUser1 = SecurityUtils.getUser();
//			System.out.println("执行修改后，当前sjid"+projUser1.getSjId());

			return R.ok(userExt.getSjId());
		} catch (Exception e) {
			e.printStackTrace();
			//还原缓存
			cache.put(username, oldUser);
			return R.failed(String.format("切换%s%s", UserTypeEnum.getDescByVal(userExt.getUserType()),"失败"));
		}
	}

	@Override
	@TxTransaction
	@Transactional(rollbackFor = Exception.class)
	public void bindSj(SysUser user) {
		//默认取第一次绑定的用户进行绑定
		SysUser sysUser = this.getById(user.getUserId());
		if (sysUser.getSjIdDefLogin()==null){
			this.updateById(user);
		}
//		System.out.println(1/0);
	}
	@Override
	@TxTransaction
	@Transactional(rollbackFor = Exception.class)
	public void unBindSj(SysUser user) {
		//默认取第一次绑定的用户进行绑定
		this.update(Wrappers.lambdaUpdate(SysUser.class).eq(SysUser::getUserId,user.getUserId()).set(SysUser::getSjIdDefLogin,user.getSjIdDefLogin()));
//		System.out.println(1/0);
	}

	@Override
	public R<BindSjVo> bindSjList(UserExtDto userExt) {
		BindSjVo vo = new BindSjVo();
		R<List> r = remoteUserExtService.getUserExtList(userExt, SecurityConstants.FROM_IN);
		List list = new ArrayList();
		list = r.getData();
		//品牌返回的参数特殊处理一下，brandName  改为name
		if (userExt.getUserType().equals(UserTypeEnum.brand.getValue())){
			String text = "brandName", newText = "name";
			List<Map<String,Object>>  brandList = list;
			brandList.stream().forEach(map->{
				map.put(newText,map.get(text));
				map.remove(text);
			});
			list = brandList;
		}

		SysUser user = this.getById(userExt.getUserId());
		Long sjId = user.getSjIdDefLogin();
		List sjList = list;
		if (sjId==null&&sjList.size()>0) {
			sjId = MapUtil.getLong((Map)sjList.get(0),"id");
			user.setSjIdDefLogin(sjId);
			this.updateById(user);
		}
		vo.setSjList(list);
		vo.setSjId(user.getSjIdDefLogin());
		vo.setUserId(user.getUserId());
		vo.setUsername(user.getUsername());
		return R.ok(vo);
	}
}
